{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "copyright-notice"
   },
   "source": [
    "#### Copyright 2017 Google LLC."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "cellView": "both",
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "copyright-notice2"
   },
   "outputs": [],
   "source": [
    "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "g4T-_IsVbweU"
   },
   "source": [
    " # 稀疏性和 L1 正则化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "g8ue2FyFIjnQ"
   },
   "source": [
    " **学习目标：**\n",
    "  * 计算模型大小\n",
    "  * 通过应用 L1 正则化来增加稀疏性，以减小模型大小"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "ME_WXE7cIjnS"
   },
   "source": [
    " 降低复杂性的一种方法是使用正则化函数，它会使权重正好为零。对于线性模型（例如线性回归），权重为零就相当于完全没有使用相应特征。除了可避免过拟合之外，生成的模型还会更加有效。\n",
    "\n",
    "L1 正则化是一种增加稀疏性的好方法。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "fHRzeWkRLrHF"
   },
   "source": [
    " ## 设置\n",
    "\n",
    "运行以下单元格，以加载数据并创建特征定义。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "pb7rSrLKIjnS"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:516: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:517: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:518: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:544: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:545: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "C:\\ProgramData\\Anaconda3\\envs\\mlcc\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:550: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
     ]
    }
   ],
   "source": [
    "from __future__ import print_function\n",
    "\n",
    "import math\n",
    "\n",
    "from IPython import display\n",
    "from matplotlib import cm\n",
    "from matplotlib import gridspec\n",
    "from matplotlib import pyplot as plt\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn import metrics\n",
    "import tensorflow as tf\n",
    "from tensorflow.python.data import Dataset\n",
    "\n",
    "tf.logging.set_verbosity(tf.logging.ERROR)\n",
    "pd.options.display.max_rows = 10\n",
    "pd.options.display.float_format = '{:.1f}'.format\n",
    "\n",
    "california_housing_dataframe = pd.read_csv(\"https://download.mlcc.google.cn/mledu-datasets/california_housing_train.csv\", sep=\",\")\n",
    "\n",
    "california_housing_dataframe = california_housing_dataframe.reindex(\n",
    "    np.random.permutation(california_housing_dataframe.index))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "3V7q8jk0IjnW"
   },
   "outputs": [],
   "source": [
    "def preprocess_features(california_housing_dataframe):\n",
    "  \"\"\"Prepares input features from California housing data set.\n",
    "\n",
    "  Args:\n",
    "    california_housing_dataframe: A Pandas DataFrame expected to contain data\n",
    "      from the California housing data set.\n",
    "  Returns:\n",
    "    A DataFrame that contains the features to be used for the model, including\n",
    "    synthetic features.\n",
    "  \"\"\"\n",
    "  selected_features = california_housing_dataframe[\n",
    "    [\"latitude\",\n",
    "     \"longitude\",\n",
    "     \"housing_median_age\",\n",
    "     \"total_rooms\",\n",
    "     \"total_bedrooms\",\n",
    "     \"population\",\n",
    "     \"households\",\n",
    "     \"median_income\"]]\n",
    "  processed_features = selected_features.copy()\n",
    "  # Create a synthetic feature.\n",
    "  processed_features[\"rooms_per_person\"] = (\n",
    "    california_housing_dataframe[\"total_rooms\"] /\n",
    "    california_housing_dataframe[\"population\"])\n",
    "  return processed_features\n",
    "\n",
    "def preprocess_targets(california_housing_dataframe):\n",
    "  \"\"\"Prepares target features (i.e., labels) from California housing data set.\n",
    "\n",
    "  Args:\n",
    "    california_housing_dataframe: A Pandas DataFrame expected to contain data\n",
    "      from the California housing data set.\n",
    "  Returns:\n",
    "    A DataFrame that contains the target feature.\n",
    "  \"\"\"\n",
    "  output_targets = pd.DataFrame()\n",
    "  # Create a boolean categorical feature representing whether the\n",
    "  # median_house_value is above a set threshold.\n",
    "  output_targets[\"median_house_value_is_high\"] = (\n",
    "    california_housing_dataframe[\"median_house_value\"] > 265000).astype(float)\n",
    "  return output_targets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "pAG3tmgwIjnY"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training examples summary:\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>latitude</th>\n",
       "      <th>longitude</th>\n",
       "      <th>housing_median_age</th>\n",
       "      <th>total_rooms</th>\n",
       "      <th>total_bedrooms</th>\n",
       "      <th>population</th>\n",
       "      <th>households</th>\n",
       "      <th>median_income</th>\n",
       "      <th>rooms_per_person</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>count</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "      <td>12000.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>mean</td>\n",
       "      <td>35.6</td>\n",
       "      <td>-119.6</td>\n",
       "      <td>28.6</td>\n",
       "      <td>2648.2</td>\n",
       "      <td>541.0</td>\n",
       "      <td>1434.5</td>\n",
       "      <td>502.5</td>\n",
       "      <td>3.9</td>\n",
       "      <td>2.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>std</td>\n",
       "      <td>2.1</td>\n",
       "      <td>2.0</td>\n",
       "      <td>12.5</td>\n",
       "      <td>2188.4</td>\n",
       "      <td>425.0</td>\n",
       "      <td>1167.9</td>\n",
       "      <td>386.4</td>\n",
       "      <td>1.9</td>\n",
       "      <td>1.2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>min</td>\n",
       "      <td>32.5</td>\n",
       "      <td>-124.3</td>\n",
       "      <td>1.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.5</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>25%</td>\n",
       "      <td>33.9</td>\n",
       "      <td>-121.8</td>\n",
       "      <td>18.0</td>\n",
       "      <td>1462.8</td>\n",
       "      <td>297.0</td>\n",
       "      <td>791.0</td>\n",
       "      <td>282.0</td>\n",
       "      <td>2.6</td>\n",
       "      <td>1.5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50%</td>\n",
       "      <td>34.2</td>\n",
       "      <td>-118.5</td>\n",
       "      <td>29.0</td>\n",
       "      <td>2127.0</td>\n",
       "      <td>434.0</td>\n",
       "      <td>1173.0</td>\n",
       "      <td>409.0</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1.9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>75%</td>\n",
       "      <td>37.7</td>\n",
       "      <td>-118.0</td>\n",
       "      <td>37.0</td>\n",
       "      <td>3168.5</td>\n",
       "      <td>653.2</td>\n",
       "      <td>1730.0</td>\n",
       "      <td>608.0</td>\n",
       "      <td>4.8</td>\n",
       "      <td>2.3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>max</td>\n",
       "      <td>42.0</td>\n",
       "      <td>-114.3</td>\n",
       "      <td>52.0</td>\n",
       "      <td>37937.0</td>\n",
       "      <td>6445.0</td>\n",
       "      <td>35682.0</td>\n",
       "      <td>6082.0</td>\n",
       "      <td>15.0</td>\n",
       "      <td>55.2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       latitude  longitude  housing_median_age  total_rooms  total_bedrooms  \\\n",
       "count   12000.0    12000.0             12000.0      12000.0         12000.0   \n",
       "mean       35.6     -119.6                28.6       2648.2           541.0   \n",
       "std         2.1        2.0                12.5       2188.4           425.0   \n",
       "min        32.5     -124.3                 1.0          8.0             1.0   \n",
       "25%        33.9     -121.8                18.0       1462.8           297.0   \n",
       "50%        34.2     -118.5                29.0       2127.0           434.0   \n",
       "75%        37.7     -118.0                37.0       3168.5           653.2   \n",
       "max        42.0     -114.3                52.0      37937.0          6445.0   \n",
       "\n",
       "       population  households  median_income  rooms_per_person  \n",
       "count     12000.0     12000.0        12000.0           12000.0  \n",
       "mean       1434.5       502.5            3.9               2.0  \n",
       "std        1167.9       386.4            1.9               1.2  \n",
       "min           3.0         1.0            0.5               0.0  \n",
       "25%         791.0       282.0            2.6               1.5  \n",
       "50%        1173.0       409.0            3.5               1.9  \n",
       "75%        1730.0       608.0            4.8               2.3  \n",
       "max       35682.0      6082.0           15.0              55.2  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Validation examples summary:\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>latitude</th>\n",
       "      <th>longitude</th>\n",
       "      <th>housing_median_age</th>\n",
       "      <th>total_rooms</th>\n",
       "      <th>total_bedrooms</th>\n",
       "      <th>population</th>\n",
       "      <th>households</th>\n",
       "      <th>median_income</th>\n",
       "      <th>rooms_per_person</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>count</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "      <td>5000.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>mean</td>\n",
       "      <td>35.6</td>\n",
       "      <td>-119.6</td>\n",
       "      <td>28.5</td>\n",
       "      <td>2632.9</td>\n",
       "      <td>535.5</td>\n",
       "      <td>1417.7</td>\n",
       "      <td>498.1</td>\n",
       "      <td>3.9</td>\n",
       "      <td>2.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>std</td>\n",
       "      <td>2.1</td>\n",
       "      <td>2.0</td>\n",
       "      <td>12.8</td>\n",
       "      <td>2159.7</td>\n",
       "      <td>413.1</td>\n",
       "      <td>1098.4</td>\n",
       "      <td>379.9</td>\n",
       "      <td>2.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>min</td>\n",
       "      <td>32.6</td>\n",
       "      <td>-124.3</td>\n",
       "      <td>2.0</td>\n",
       "      <td>2.0</td>\n",
       "      <td>2.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>2.0</td>\n",
       "      <td>0.5</td>\n",
       "      <td>0.1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>25%</td>\n",
       "      <td>33.9</td>\n",
       "      <td>-121.8</td>\n",
       "      <td>18.0</td>\n",
       "      <td>1461.0</td>\n",
       "      <td>296.8</td>\n",
       "      <td>787.0</td>\n",
       "      <td>280.0</td>\n",
       "      <td>2.6</td>\n",
       "      <td>1.5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50%</td>\n",
       "      <td>34.3</td>\n",
       "      <td>-118.5</td>\n",
       "      <td>29.0</td>\n",
       "      <td>2130.0</td>\n",
       "      <td>433.0</td>\n",
       "      <td>1154.0</td>\n",
       "      <td>407.0</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1.9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>75%</td>\n",
       "      <td>37.7</td>\n",
       "      <td>-118.0</td>\n",
       "      <td>37.0</td>\n",
       "      <td>3107.0</td>\n",
       "      <td>637.0</td>\n",
       "      <td>1700.0</td>\n",
       "      <td>595.0</td>\n",
       "      <td>4.8</td>\n",
       "      <td>2.3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>max</td>\n",
       "      <td>41.9</td>\n",
       "      <td>-114.6</td>\n",
       "      <td>52.0</td>\n",
       "      <td>30401.0</td>\n",
       "      <td>4957.0</td>\n",
       "      <td>15037.0</td>\n",
       "      <td>4372.0</td>\n",
       "      <td>15.0</td>\n",
       "      <td>34.2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       latitude  longitude  housing_median_age  total_rooms  total_bedrooms  \\\n",
       "count    5000.0     5000.0              5000.0       5000.0          5000.0   \n",
       "mean       35.6     -119.6                28.5       2632.9           535.5   \n",
       "std         2.1        2.0                12.8       2159.7           413.1   \n",
       "min        32.6     -124.3                 2.0          2.0             2.0   \n",
       "25%        33.9     -121.8                18.0       1461.0           296.8   \n",
       "50%        34.3     -118.5                29.0       2130.0           433.0   \n",
       "75%        37.7     -118.0                37.0       3107.0           637.0   \n",
       "max        41.9     -114.6                52.0      30401.0          4957.0   \n",
       "\n",
       "       population  households  median_income  rooms_per_person  \n",
       "count      5000.0      5000.0         5000.0            5000.0  \n",
       "mean       1417.7       498.1            3.9               2.0  \n",
       "std        1098.4       379.9            2.0               1.0  \n",
       "min           6.0         2.0            0.5               0.1  \n",
       "25%         787.0       280.0            2.6               1.5  \n",
       "50%        1154.0       407.0            3.5               1.9  \n",
       "75%        1700.0       595.0            4.8               2.3  \n",
       "max       15037.0      4372.0           15.0              34.2  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training targets summary:\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>median_house_value_is_high</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>count</td>\n",
       "      <td>12000.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>mean</td>\n",
       "      <td>0.2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>std</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>min</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>25%</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50%</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>75%</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>max</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       median_house_value_is_high\n",
       "count                     12000.0\n",
       "mean                          0.2\n",
       "std                           0.4\n",
       "min                           0.0\n",
       "25%                           0.0\n",
       "50%                           0.0\n",
       "75%                           0.0\n",
       "max                           1.0"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Validation targets summary:\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>median_house_value_is_high</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>count</td>\n",
       "      <td>5000.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>mean</td>\n",
       "      <td>0.3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>std</td>\n",
       "      <td>0.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>min</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>25%</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50%</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>75%</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>max</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       median_house_value_is_high\n",
       "count                      5000.0\n",
       "mean                          0.3\n",
       "std                           0.4\n",
       "min                           0.0\n",
       "25%                           0.0\n",
       "50%                           0.0\n",
       "75%                           1.0\n",
       "max                           1.0"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Choose the first 12000 (out of 17000) examples for training.\n",
    "training_examples = preprocess_features(california_housing_dataframe.head(12000))\n",
    "training_targets = preprocess_targets(california_housing_dataframe.head(12000))\n",
    "\n",
    "# Choose the last 5000 (out of 17000) examples for validation.\n",
    "validation_examples = preprocess_features(california_housing_dataframe.tail(5000))\n",
    "validation_targets = preprocess_targets(california_housing_dataframe.tail(5000))\n",
    "\n",
    "# Double-check that we've done the right thing.\n",
    "print(\"Training examples summary:\")\n",
    "display.display(training_examples.describe())\n",
    "print(\"Validation examples summary:\")\n",
    "display.display(validation_examples.describe())\n",
    "\n",
    "print(\"Training targets summary:\")\n",
    "display.display(training_targets.describe())\n",
    "print(\"Validation targets summary:\")\n",
    "display.display(validation_targets.describe())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "gHkniRI1Ijna"
   },
   "outputs": [],
   "source": [
    "def my_input_fn(features, targets, batch_size=1, shuffle=True, num_epochs=None):\n",
    "    \"\"\"Trains a linear regression model.\n",
    "  \n",
    "    Args:\n",
    "      features: pandas DataFrame of features\n",
    "      targets: pandas DataFrame of targets\n",
    "      batch_size: Size of batches to be passed to the model\n",
    "      shuffle: True or False. Whether to shuffle the data.\n",
    "      num_epochs: Number of epochs for which data should be repeated. None = repeat indefinitely\n",
    "    Returns:\n",
    "      Tuple of (features, labels) for next data batch\n",
    "    \"\"\"\n",
    "  \n",
    "    # Convert pandas data into a dict of np arrays.\n",
    "    features = {key:np.array(value) for key,value in dict(features).items()}                                            \n",
    " \n",
    "    # Construct a dataset, and configure batching/repeating.\n",
    "    ds = Dataset.from_tensor_slices((features,targets)) # warning: 2GB limit\n",
    "    ds = ds.batch(batch_size).repeat(num_epochs)\n",
    "    \n",
    "    # Shuffle the data, if specified.\n",
    "    if shuffle:\n",
    "      ds = ds.shuffle(10000)\n",
    "    \n",
    "    # Return the next batch of data.\n",
    "    features, labels = ds.make_one_shot_iterator().get_next()\n",
    "    return features, labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "bLzK72jkNJPf"
   },
   "outputs": [],
   "source": [
    "def get_quantile_based_buckets(feature_values, num_buckets):\n",
    "  quantiles = feature_values.quantile(\n",
    "    [(i+1.)/(num_buckets + 1.) for i in range(num_buckets)])\n",
    "  return [quantiles[q] for q in quantiles.keys()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "al2YQpKyIjnd"
   },
   "outputs": [],
   "source": [
    "def construct_feature_columns():\n",
    "  \"\"\"Construct the TensorFlow Feature Columns.\n",
    "\n",
    "  Returns:\n",
    "    A set of feature columns\n",
    "  \"\"\"\n",
    "\n",
    "  bucketized_households = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"households\"),\n",
    "    boundaries=get_quantile_based_buckets(training_examples[\"households\"], 10))\n",
    "  bucketized_longitude = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"longitude\"),\n",
    "    boundaries=get_quantile_based_buckets(training_examples[\"longitude\"], 50))\n",
    "  bucketized_latitude = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"latitude\"),\n",
    "    boundaries=get_quantile_based_buckets(training_examples[\"latitude\"], 50))\n",
    "  bucketized_housing_median_age = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"housing_median_age\"),\n",
    "    boundaries=get_quantile_based_buckets(\n",
    "      training_examples[\"housing_median_age\"], 10))\n",
    "  bucketized_total_rooms = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"total_rooms\"),\n",
    "    boundaries=get_quantile_based_buckets(training_examples[\"total_rooms\"], 10))\n",
    "  bucketized_total_bedrooms = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"total_bedrooms\"),\n",
    "    boundaries=get_quantile_based_buckets(training_examples[\"total_bedrooms\"], 10))\n",
    "  bucketized_population = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"population\"),\n",
    "    boundaries=get_quantile_based_buckets(training_examples[\"population\"], 10))\n",
    "  bucketized_median_income = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"median_income\"),\n",
    "    boundaries=get_quantile_based_buckets(training_examples[\"median_income\"], 10))\n",
    "  bucketized_rooms_per_person = tf.feature_column.bucketized_column(\n",
    "    tf.feature_column.numeric_column(\"rooms_per_person\"),\n",
    "    boundaries=get_quantile_based_buckets(\n",
    "      training_examples[\"rooms_per_person\"], 10))\n",
    "\n",
    "  long_x_lat = tf.feature_column.crossed_column(\n",
    "    set([bucketized_longitude, bucketized_latitude]), hash_bucket_size=1000)\n",
    "\n",
    "  feature_columns = set([\n",
    "    long_x_lat,\n",
    "    bucketized_longitude,\n",
    "    bucketized_latitude,\n",
    "    bucketized_housing_median_age,\n",
    "    bucketized_total_rooms,\n",
    "    bucketized_total_bedrooms,\n",
    "    bucketized_population,\n",
    "    bucketized_households,\n",
    "    bucketized_median_income,\n",
    "    bucketized_rooms_per_person])\n",
    "  \n",
    "  return feature_columns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "hSBwMrsrE21n"
   },
   "source": [
    " ## 计算模型大小\n",
    "\n",
    "要计算模型大小，只需计算非零参数的数量即可。为此，我们在下面提供了一个辅助函数。该函数深入使用了 Estimator API，如果不了解它的工作原理，也不用担心。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "e6GfTI0CFhB8"
   },
   "outputs": [],
   "source": [
    "def model_size(estimator):\n",
    "  variables = estimator.get_variable_names()\n",
    "  size = 0\n",
    "  for variable in variables:\n",
    "    if not any(x in variable \n",
    "               for x in ['global_step',\n",
    "                         'centered_bias_weight',\n",
    "                         'bias_weight',\n",
    "                         'Ftrl']\n",
    "              ):\n",
    "      size += np.count_nonzero(estimator.get_variable_value(variable))\n",
    "  return size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "XabdAaj67GfF"
   },
   "source": [
    " ## 减小模型大小\n",
    "\n",
    "您的团队需要针对 *SmartRing* 构建一个准确度高的逻辑回归模型，这种指环非常智能，可以感应城市街区的人口统计特征（`median_income`、`avg_rooms`、`households` 等等），并告诉您指定城市街区的住房成本是否高昂。\n",
    "\n",
    "由于 SmartRing 很小，因此工程团队已确定它只能处理**参数数量不超过 600 个**的模型。另一方面，产品管理团队也已确定，除非所保留测试集的**对数损失函数低于 0.35**，否则该模型不能发布。\n",
    "\n",
    "您可以使用秘密武器“L1 正则化”调整模型，使其同时满足大小和准确率限制条件吗？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "G79hGRe7qqej"
   },
   "source": [
    " ### 任务 1：查找合适的正则化系数。\n",
    "\n",
    "**查找可同时满足以下两种限制条件的 L1 正则化强度参数：模型的参数数量不超过 600 个且验证集的对数损失函数低于 0.35。**\n",
    "\n",
    "以下代码可帮助您快速开始。您可以通过多种方法向您的模型应用正则化。在此练习中，我们选择使用 `FtrlOptimizer` 来应用正则化。`FtrlOptimizer` 是一种设计成使用 L1 正则化比标准梯度下降法得到更好结果的方法。\n",
    "\n",
    "重申一次，我们会使用整个数据集来训练该模型，因此预计其运行速度会比通常要慢。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "1Fcdm0hpIjnl"
   },
   "outputs": [],
   "source": [
    "def train_linear_classifier_model(\n",
    "    learning_rate,\n",
    "    regularization_strength,\n",
    "    steps,\n",
    "    batch_size,\n",
    "    feature_columns,\n",
    "    training_examples,\n",
    "    training_targets,\n",
    "    validation_examples,\n",
    "    validation_targets):\n",
    "  \"\"\"Trains a linear regression model.\n",
    "  \n",
    "  In addition to training, this function also prints training progress information,\n",
    "  as well as a plot of the training and validation loss over time.\n",
    "  \n",
    "  Args:\n",
    "    learning_rate: A `float`, the learning rate.\n",
    "    regularization_strength: A `float` that indicates the strength of the L1\n",
    "       regularization. A value of `0.0` means no regularization.\n",
    "    steps: A non-zero `int`, the total number of training steps. A training step\n",
    "      consists of a forward and backward pass using a single batch.\n",
    "    feature_columns: A `set` specifying the input feature columns to use.\n",
    "    training_examples: A `DataFrame` containing one or more columns from\n",
    "      `california_housing_dataframe` to use as input features for training.\n",
    "    training_targets: A `DataFrame` containing exactly one column from\n",
    "      `california_housing_dataframe` to use as target for training.\n",
    "    validation_examples: A `DataFrame` containing one or more columns from\n",
    "      `california_housing_dataframe` to use as input features for validation.\n",
    "    validation_targets: A `DataFrame` containing exactly one column from\n",
    "      `california_housing_dataframe` to use as target for validation.\n",
    "      \n",
    "  Returns:\n",
    "    A `LinearClassifier` object trained on the training data.\n",
    "  \"\"\"\n",
    "\n",
    "  periods = 7\n",
    "  steps_per_period = steps / periods\n",
    "\n",
    "  # Create a linear classifier object.\n",
    "  my_optimizer = tf.train.FtrlOptimizer(learning_rate=learning_rate, l1_regularization_strength=regularization_strength)\n",
    "  my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)\n",
    "  linear_classifier = tf.estimator.LinearClassifier(\n",
    "      feature_columns=feature_columns,\n",
    "      optimizer=my_optimizer\n",
    "  )\n",
    "  \n",
    "  # Create input functions.\n",
    "  training_input_fn = lambda: my_input_fn(training_examples, \n",
    "                                          training_targets[\"median_house_value_is_high\"], \n",
    "                                          batch_size=batch_size)\n",
    "  predict_training_input_fn = lambda: my_input_fn(training_examples, \n",
    "                                                  training_targets[\"median_house_value_is_high\"], \n",
    "                                                  num_epochs=1, \n",
    "                                                  shuffle=False)\n",
    "  predict_validation_input_fn = lambda: my_input_fn(validation_examples, \n",
    "                                                    validation_targets[\"median_house_value_is_high\"], \n",
    "                                                    num_epochs=1, \n",
    "                                                    shuffle=False)\n",
    "  \n",
    "  # Train the model, but do so inside a loop so that we can periodically assess\n",
    "  # loss metrics.\n",
    "  print(\"Training model...\")\n",
    "  print(\"LogLoss (on validation data):\")\n",
    "  training_log_losses = []\n",
    "  validation_log_losses = []\n",
    "  for period in range (0, periods):\n",
    "    # Train the model, starting from the prior state.\n",
    "    linear_classifier.train(\n",
    "        input_fn=training_input_fn,\n",
    "        steps=steps_per_period\n",
    "    )\n",
    "    # Take a break and compute predictions.\n",
    "    training_probabilities = linear_classifier.predict(input_fn=predict_training_input_fn)\n",
    "    training_probabilities = np.array([item['probabilities'] for item in training_probabilities])\n",
    "    \n",
    "    validation_probabilities = linear_classifier.predict(input_fn=predict_validation_input_fn)\n",
    "    validation_probabilities = np.array([item['probabilities'] for item in validation_probabilities])\n",
    "    \n",
    "    # Compute training and validation loss.\n",
    "    training_log_loss = metrics.log_loss(training_targets, training_probabilities)\n",
    "    validation_log_loss = metrics.log_loss(validation_targets, validation_probabilities)\n",
    "    # Occasionally print the current loss.\n",
    "    print(\"  period %02d : %0.2f\" % (period, validation_log_loss))\n",
    "    # Add the loss metrics from this period to our list.\n",
    "    training_log_losses.append(training_log_loss)\n",
    "    validation_log_losses.append(validation_log_loss)\n",
    "  print(\"Model training finished.\")\n",
    "\n",
    "  # Output a graph of loss metrics over periods.\n",
    "  plt.ylabel(\"LogLoss\")\n",
    "  plt.xlabel(\"Periods\")\n",
    "  plt.title(\"LogLoss vs. Periods\")\n",
    "  plt.tight_layout()\n",
    "  plt.plot(training_log_losses, label=\"training\")\n",
    "  plt.plot(validation_log_losses, label=\"validation\")\n",
    "  plt.legend()\n",
    "\n",
    "  return linear_classifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "9H1CKHSzIjno"
   },
   "outputs": [],
   "source": [
    "linear_classifier = train_linear_classifier_model(\n",
    "    learning_rate=0.1,\n",
    "    # TWEAK THE REGULARIZATION VALUE BELOW\n",
    "    regularization_strength=0.0,\n",
    "    steps=300,\n",
    "    batch_size=100,\n",
    "    feature_columns=construct_feature_columns(),\n",
    "    training_examples=training_examples,\n",
    "    training_targets=training_targets,\n",
    "    validation_examples=validation_examples,\n",
    "    validation_targets=validation_targets)\n",
    "print(\"Model size:\", model_size(linear_classifier))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "yjUCX5LAkxAX"
   },
   "source": [
    " ### 解决方案\n",
    "\n",
    "点击下方即可查看可能的解决方案。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "hgGhy-okmkWL"
   },
   "source": [
    " 正则化强度为 0.1 应该就足够了。请注意，有一个需要做出折中选择的地方：正则化越强，我们获得的模型就越小，但会影响分类损失。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "autoexec": {
      "startup": false,
      "wait_interval": 0
     }
    },
    "colab_type": "code",
    "id": "_rV8YQWZIjns"
   },
   "outputs": [],
   "source": [
    "linear_classifier = train_linear_classifier_model(\n",
    "    learning_rate=0.1,\n",
    "    regularization_strength=0.1,\n",
    "    steps=300,\n",
    "    batch_size=100,\n",
    "    feature_columns=construct_feature_columns(),\n",
    "    training_examples=training_examples,\n",
    "    training_targets=training_targets,\n",
    "    validation_examples=validation_examples,\n",
    "    validation_targets=validation_targets)\n",
    "print(\"Model size:\", model_size(linear_classifier))"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [
    "yjUCX5LAkxAX",
    "copyright-notice"
   ],
   "default_view": {},
   "name": "sparsity_and_l1_regularization.ipynb",
   "provenance": [],
   "version": "0.3.2",
   "views": {}
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
